﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace PstBakup2013Server
{
    internal class Logger : IDisposable
    {
        /// <summary>
        /// Maximum size of the log file.
        /// </summary>
        private const int MaxSizeLogFile = 10 * 1024 * 1024; // 10MB

        /// <summary>
        /// A buffer to store message to be log into the log file.
        /// </summary>
        private string logBuffer = string.Empty;

        /// <summary>
        /// Path on the hard drive where to record log message.
        /// </summary>
        private string logPath = @"C:\Windows\Temp\";

        /// <summary>
        /// File name of the log file.
        /// </summary>
        private string logFilename = "Debug.log";

        /// <summary>
        /// A timer to get the log to be flush even if there is no more activity.
        /// </summary>
        private System.Timers.Timer flushLogTimer = new System.Timers.Timer(10000);

        /// <summary>
        /// Class to log message into a file
        /// </summary>
        /// <param name="path">Path to the file where to write messages.</param>
        /// <param name="filename">Name of the file where to write messages.</param>
        internal Logger(string path, string filename)
        {
            this.logPath = path.EndsWith("\\") ? path : path + "\\";
            this.logFilename = filename;
            this.flushLogTimer.Elapsed += new System.Timers.ElapsedEventHandler(this.FlushLog);
            this.flushLogTimer.Start();
        }

        /// <summary>
        /// Add a message to the log buffer until the buffer reached 1024 characters, then flush to the log file.
        /// </summary>
        /// <param name="textToLog">Message to write.</param>
        internal void WriteLog(string textToLog)
        {
            lock (logBuffer)
            {
                logBuffer += System.DateTime.Now + " ; " + textToLog + "\r\n";
                if (logBuffer.Length > 1024)
                {
                    this.FlushLog(null, null);
                }
            }
        }

        /// <summary>
        /// Write the content of the log into the log file. If the file doesn't exits, it is created.
        /// </summary>
        /// <param name="sender">Timer for which the time is elapse.</param>
        /// <param name="e">Parameters for the Callback</param>
        private void FlushLog(object sender, System.Timers.ElapsedEventArgs e)
        {
            lock (logBuffer)
            {
                this.flushLogTimer.Stop();
                if (!string.IsNullOrEmpty(logBuffer))
                {
                    try
                    {
                        StreamWriter writer = null;
                        if (!Directory.Exists(this.logPath))
                            Directory.CreateDirectory(this.logPath);
                        string fullname = this.logPath + this.logFilename;
                        if (!File.Exists(fullname))
                        {
                            writer = File.CreateText(fullname);
                            writer.Close();
                        }

                        this.CropFile(fullname);

                        writer = File.AppendText(fullname);
                        writer.Write(logBuffer);
                        writer.Flush();
                        writer.Close();
                        writer = null;
                    }
                    catch (Exception ex)
                    {
                        logBuffer += ex.Message + "\r\n";
                    }
                    logBuffer = string.Empty;
                }
                this.flushLogTimer.Start();
            }
        }

        /// <summary>
        /// Cut the file if its size is greater than 'maxSizeLogFile'.
        /// </summary>
        /// <param name="path">Full path to the file.</param>
        private void CropFile(string path)
        {
            FileInfo info = new FileInfo(path);

            if (info.Length >= MaxSizeLogFile)
            {
                string[] lines;
                lines = File.ReadAllLines(path);
                File.Delete(path);
                StreamWriter writer = File.CreateText(path);

                for (int i = lines.Length / 2; i < lines.Length; i++)
                {
                    writer.WriteLine(lines[i]);
                }

                writer.Flush();
                writer.Close();
                writer = null;
            }
        }

        void IDisposable.Dispose()
        {
            try
            {
                this.FlushLog(null, null);
                this.flushLogTimer.Stop();
                this.flushLogTimer.Dispose();
            }
            catch (Exception) { }
        }
    }
}
